/*
 * @(#)ConfigContext.java 1.0 2019年2月15日下午5:12:22
 *
 * 
 * Copyright (c) , Inc. All rights reserved.a
 */
package com.saturn.cloud.config.util;

import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;

import cn.hutool.core.util.StrUtil;

/**
 * <dl>
 * <dt><b>Title:</b></dt>
 * <dd>none</dd>
 * <dt><b>Description:</b></dt>
 * <dd>
 * <p>
 * none</dd>
 * </dl>
 *
 * @author tanks
 * @version 1.0, 2019年2月15日
 * @since saturn-utils
 * 
 */
public class ConfigContext {

	private static ApplicationContext applicationContext;
	private static final Logger logger = LoggerFactory.getLogger(ConfigContext.class);
	private static Map<String, Object> configs = new ConcurrentHashMap<String, Object>();
	private static Environment environment ;

	public static Map<String,Object> getConfigs(){
		return configs;
	}

	/**
	 * 初始化数据
	 */
	public static void init() {
		if( applicationContext==null ) {
			System.out.println("*---------------------------------------------------------------------------------------------------*\n" + 
					"*   _____       _                       _____             __ _          _____ _ _            _      *\n" + 
					"*  / ____|     | |                     / ____|           / _(_)        / ____| (_)          | |     *\n" + 
					"* | (___   __ _| |_ _ __ _   _ _ __   | |     ___  _ __ | |_ _  __ _  | |    | |_  ___ _ __ | |_    *\n" + 
					"*  \\___ \\ / _` | __| '__| | | | '_ \\  | |    / _ \\| '_ \\|  _| |/ _` | | |    | | |/ _ \\ '_ \\| __|   *\n" + 
					"*  ____) | (_| | |_| |  | |_| | | | | | |___| (_) | | | | | | | (_| | | |____| | |  __/ | | | |_    *\n" + 
					"* |_____/ \\__,_|\\__|_|   \\__,_|_| |_|  \\_____\\___/|_| |_|_| |_|\\__, |  \\_____|_|_|\\___|_| |_|\\__|   *\n" + 
					"*                                                               __/ |                               *\n" + 
					"*                                                              |___/                Version:1.0.0   *\n" + 
					"*---------------------------------------------------------------------------------------------------* ");
		}
	}
	
	/**
	 * 获取配置属性
	 * @param configKey
	 * @return
	 */
	public static String getValue(String configKey) {
		if( environment==null ) return null;
		return environment.getProperty(configKey);
	}
	
	/**
	 * 获取容器所有配置的值对象
	 * @return
	 */
	public static MutablePropertySources getPropertySources() {
		Environment environment = applicationContext.getEnvironment();
		if (environment instanceof ConfigurableEnvironment) {
			return ((ConfigurableEnvironment) environment).getPropertySources();
		}
		return new StandardEnvironment().getPropertySources();
	}
	
	public static Map<String, PropertySource<?>> getPropertySourcesAsMap() {
		Map<String, PropertySource<?>> map = new LinkedHashMap<>();
		for (PropertySource<?> source : getPropertySources()) {
			if (!ConfigurationPropertySources
					.isAttachedConfigurationPropertySource(source)) {
				extract(StrUtil.EMPTY, map, source);
			}
		}
		return map;
	}
	
	public static void extract(String root, Map<String, PropertySource<?>> map,PropertySource<?> source) {
		if (source instanceof CompositePropertySource) {
			for (PropertySource<?> nest : ((CompositePropertySource) source).getPropertySources()) {
				extract(source.getName() + ":", map, nest);
			}
		}
		else {
			map.put(root + source.getName(), source);
		}
	}
	
	

	/**
	 * 设置系统环境变量
	 * 
	 * @param key
	 * @param ob
	 */
	public synchronized static void setApplicationContext(String key, Object ob) {
		if (StrUtil.isBlank(key)) {
			logMessage("【全局变量】全局变量添加失败，传入Key为空");
			return;
		}
		Object existOb = configs.get(key);
		if (null != existOb) {
			logMessage("【全局变量设置失败】存放对象已存在,key=" + key + ",value=" + ob.toString());
			return;
		}
		logMessage("【全局变量】添加全局变量key=" + key + ",value=" + ob.toString());
		configs.put(key, ob);
	}

	/**
	 * 更新系统参数变量
	 * 
	 * @param key
	 * @param ob
	 */
	public synchronized static void updateApplicationContext(String key, Object ob) {
		if (StrUtil.isBlank(key)) {
			logMessage("【全局变量】全局变量更新失败，传入Key为空,key=" + key + ",value=" + ob);
			return;
		}
		if (configs.containsKey(key)) {
			Object oldValue = configs.remove(key);
			logMessage("【全局变量】更新全局变量,key=" + key + ",OldValue=" + oldValue);
		}
		logMessage("【全局变量】更新全局变量,key=" + key + ",value=" + ob);
		configs.put(key, ob);
	}

	/**
	 * 删除系统参数变量
	 * 
	 * @param key
	 */
	public synchronized static void removeApplicationContext(String key) {
		if (StrUtil.isBlank(key)) {
			logMessage("【全局变量】全局变量删除失败，传入Key为空");
			return;
		}
		if (configs.containsKey(key)) {
			Object oldValue = configs.remove(key);
			logMessage("【全局变量】全局变量删除,key=" + key + ",OldValue=" + oldValue);
		} else {
			logMessage("【全局变量】全局变量不存在,无法删除,key=" + key);
		}
	}

	/**
	 * 系统关闭时,需销毁持有参数
	 * 
	 * @param key
	 * @return
	 */
	public static Object getApplicationContext(String key) {
		if (StrUtil.isBlank(key)) {
			logMessage("【全局变量】全局变量获取失败，传入Key为空");
			return null;
		}
		if( configs.containsKey(key) ) {
			return configs.get(key);
		}else {
			return getValue(key);
		}
	}

	/**
	 * 把系统配置的参数转换为Properties对象
	 * 
	 * @return
	 */
	public static Properties getConfigProperties() {
		Properties props = new Properties();
		if (configs != null && configs.size() > 0) {
			for (Iterator<String> it = configs.keySet().iterator(); it.hasNext();) {
				String key = it.next();
				Object value = configs.get(key);
				props.put(key, value);
			}
		}
		return props;
	}

	public static void destroy() {
		configs.clear();
	}

	/**
	 * 输出日志信息
	 * 
	 * @param servletContext
	 * @param msg
	 */
	private static void logMessage(String msg) {
		logger.info(msg);
	}
	
	public static void setApplicationContext(ApplicationContext applicationContext) {
		if( ConfigContext.applicationContext==null ) {
			ConfigContext.applicationContext = applicationContext;
			ConfigContext.environment = applicationContext.getEnvironment();
		}
	}
	
}
